/*   _________  __  ____________  ___   ___  ____
 *  / ___/ __ \/  |/  /_  __/ _ \/ _ | / _ \/ __/
 * / /__/ /_/ / /|_/ / / / / , _/ __ |/ // / _/  
 * \___/\____/_/  /_/ /_/ /_/|_/_/ |_/____/___/  
 * COMTRADE file parser
 * -------------------------------------------------------------------------
 * Copyright (C) 2013 - Ericson Norberto A Santos (ericsonnorberto@gmail.com)
 * Federal University Of Campina Grande - UFCG
 * 
 * Supports on IEEE Std C37.111-1999 COMTRADE-99 and IEEE Std C37.111-1991
 * COMTRADE-91 standards.
 * 
 * ABSTRACT:
 * A common format for data files and exchange medium used for the interchange
 * of various types of fault, test, or simulation data for electrical power
 * systems is defined. Sources of transient data are described, and the case of
 * diskettes as an exchange medium is recommended.
 * Issues of sampling rates, filters, and sample rate conversions for transient
 * data being exchanged are discussed. Files for data exchange are specified,
 * as is the organization of the data. A sample file is given.
 * 
 * License information:
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
*/
#include <math.h>

#include "COMTRADE_parse.hpp"

COMTRADE_parse::COMTRADE_parse()
{
    /* Found file flags */
    cfg_parse_file = false;
    dat_parse_file = false;
    hdr_parse_file = false;
    inf_parse_file = false;
    
    /* dat file total records */
    dat_total_records = 0;
    dat_size_of_file  = 0;
}

COMTRADE_parse::~COMTRADE_parse()
{
    /* Close file stream */
    for (int i=0; i<4; i++)
    {
        if (file_stream[i].is_open())
        {
            file_stream[i].close();
        }
    }
}

int COMTRADE_parse::COMTRADE_open_file(const string& filename)
{
    string file_name, file_type[4] = {".cfg", ".inf", ".hdr", ".dat"};
    
    for (int i=0; i<4; i++)
    {
        comtrade_file_list temp_file_list;
        
        /* Generate file name */
        file_name.clear();
        file_name.append("./");
        file_name.append(filename);
        file_name.append(file_type[i]);

        /* Save information of files */
        switch (i)
        {
            case COMTRADE_FILE_CFG:
            {
                if (COMTRADE_file_exists(file_name) == false)
                {
                    return ERROR_FILE_NOT_FOUND;
                }
                else
                {
                    temp_file_list.file_exist = true;
                    temp_file_list.file_name  = file_name;
                }
                break;
            }
            case COMTRADE_FILE_DAT:
            {
                if (COMTRADE_file_exists(file_name) == false)
                {
                    return ERROR_FILE_NOT_FOUND;
                }
                else
                {
                    temp_file_list.file_exist = true;
                    temp_file_list.file_name  = file_name;
                }
                break;
            }
            case COMTRADE_FILE_INF:
            {
                if (COMTRADE_file_exists(file_name) == false)
                {
                    temp_file_list.file_exist = false;
                }
                else
                {
                    temp_file_list.file_exist = true;
                }
                temp_file_list.file_name  = file_name;
                break;
            }
            case COMTRADE_FILE_HDR:
            {
                if (COMTRADE_file_exists(file_name) == false)
                {
                    temp_file_list.file_exist = false;
                }
                else
                {
                    temp_file_list.file_exist = true;
                }
                temp_file_list.file_name  = file_name;
                break;
            }
        }
        file_list.push_back(temp_file_list);
        cout << "File [" << i << "] " << file_name << endl;
    }
    
    /* Open text files only */
    for (int i=0; i<3; i++)
    {
        if (file_list[i].file_exist == true)
        {
            file_stream[i].open(file_list[i].file_name.c_str(), ifstream::in);
        }
        if (file_stream[i].is_open() == false)
        {
            return ERROR_OPEN_FILE;
        }
    }
    
    return ERROR_NO_ERROR;
}

bool COMTRADE_parse::COMTRADE_file_exists(const string& filename)
{
    struct stat info;
    int ret = -1;

    ret = stat(filename.c_str(), &info);
    if (ret == 0) 
    {
        return true;
    } 
    else 
    {
        return false;
    }
}

int COMTRADE_parse::COMTRADE_parse_cfg_file()
{
    /* Check if cfg file is parsed */
    if (cfg_parse_file)
    {
        return -1;
    }
    
    /* Line stream buffer */
    string line_buffer;
    
    /* Tokens information */
    string gi_token[3];
    string ci_token[3];
    string ac_token[13];
    string dc_token[5];
    string lf_token[1];
    string sr_token[3];
    string dt_token[4];
    string ft_token[1];
    string ts_token[1];
    
    /* Line and column counters */
    int i = 0;
    int j = 0;
    
    /* Found pointers */    
    size_t found_new = 0;
    size_t found_old = 0;
    
    /* Read first line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    gi_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        gi_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }
    
    /* Save information data */
    configuration_file.general_information.station_name = gi_token[0];
    configuration_file.general_information.rec_dev_id   = gi_token[1];
    configuration_file.general_information.rev_year     = gi_token[2];
    
    if (configuration_file.general_information.rev_year == "1999")
    {
        /* IEEE Std C31.111-1999 COMTRADE-99 file format */
    }
    else
    {
        /* IEEE Std C31.111-1991 COMTRADE-91 file format */
    }
    
    
    /* Reset variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i = 0;
    
    /* Read second line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    ci_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        ci_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }

    /* Save information data */
    configuration_file.channel_information.ch_tt = atoi(ci_token[0].c_str());
    if ((ci_token[1].substr(ci_token[1].size()-1, 1) == "A") || (ci_token[1].substr(ci_token[1].size()-1, 1) == "a"))
    {
        configuration_file.channel_information.ch_ta = atoi(ci_token[1].substr(0, ci_token[1].size()-1).c_str());
    }
    if ((ci_token[2].substr(ci_token[2].size()-1, 1) == "D") || (ci_token[2].substr(ci_token[2].size()-1, 1) == "d"))
    {
        configuration_file.channel_information.ch_td = atoi(ci_token[2].substr(0, ci_token[2].size()-1).c_str());
    }
    
    /* Read analog channel information */
    for (j=0; j<configuration_file.channel_information.ch_ta; j++)
    {
        /* Reset variables */
        line_buffer.clear();
        found_new = 0;
        found_old = 0;
        i = 0;
    
        /* Read next line */
        getline(file_stream[COMTRADE_FILE_CFG], line_buffer);

        /* Parse line buffer */
        found_new = line_buffer.find(",");
        found_old = found_new+1;
        ac_token[i] = line_buffer.substr(0, found_new);
        while (found_new != std::string::npos)
        {
            found_new = line_buffer.find(",", found_old);
            i++;
            ac_token[i] = line_buffer.substr(found_old, found_new-found_old);
            found_old = found_new+1;
        }
        
        /* Temporary vector */
        config_analog_channel_information temp_analog_channel;
        
        /* Get information data */
        temp_analog_channel.ch_Ac    = atoi(ac_token[0].c_str());
        temp_analog_channel.ch_id    = ac_token[1];
        temp_analog_channel.ch_phase = ac_token[2];
        temp_analog_channel.ch_ccbm  = ac_token[3];
        temp_analog_channel.ch_units = ac_token[4];
        temp_analog_channel.ch_a     = atof(ac_token[5].c_str());
        temp_analog_channel.ch_b     = atof(ac_token[6].c_str());
        temp_analog_channel.ch_skew  = atof(ac_token[7].c_str());
        temp_analog_channel.ch_min   = atoi(ac_token[8].c_str());
        temp_analog_channel.ch_max   = atoi(ac_token[9].c_str());
        /* IEEE Std C31.111-1999 format only */
        temp_analog_channel.ch_pri_v = atof(ac_token[10].c_str());
        temp_analog_channel.ch_sec_v = atof(ac_token[11].c_str());
        temp_analog_channel.ch_PS    = ac_token[12];
        
        /* Save information data vector */
        configuration_file.analog_channel_information.push_back(temp_analog_channel);
    }
    
    /* Read digital channel information */
    for (j=0; j<configuration_file.channel_information.ch_td; j++)
    {
        /* Reset variables */
        line_buffer.clear();
        found_new = 0;
        found_old = 0;
        i = 0;
    
        /* Read next line */
        getline(file_stream[COMTRADE_FILE_CFG], line_buffer);

        /* Parse line buffer */
        found_new = line_buffer.find(",");
        found_old = found_new+1;
        dc_token[i] = line_buffer.substr(0, found_new);
        while (found_new != std::string::npos)
        {
            found_new = line_buffer.find(",", found_old);
            i++;
            dc_token[i] = line_buffer.substr(found_old, found_new-found_old);
            found_old = found_new+1;
        }
        
        /* Temporary vector */
        config_digital_channel_information temp_digital_channel;
        
        /* Get information data */
        temp_digital_channel.ch_Dn     = atoi(dc_token[0].c_str());
        temp_digital_channel.ch_id     = dc_token[1];
        /* IEEE Std C31.111-1999 format only */
        temp_digital_channel.ch_phase  = dc_token[2];
        temp_digital_channel.ch_ccbm   = dc_token[3];
        /* --------------------------------- */
        temp_digital_channel.ch_nstate = atoi(dc_token[4].c_str());
        
        /* Save information data vector */
        configuration_file.digital_channel_information.push_back(temp_digital_channel);
    }
    
    /* Frequency information */
    
    /* Reset variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i = 0;
    
    /* Read second line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    lf_token[i] = line_buffer.substr(0, found_new);
    
    /* Save data information */
    configuration_file.line_frequency.line_frequency = atof(lf_token[0].c_str());
    
    /* Sampling rate information */
    
    /* Reset variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i = 0;
    
    /* Read line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    sr_token[i] = line_buffer.substr(0, found_new);
    
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i++;
    
    /* Read line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    sr_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        sr_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }
    
    /* Save data information */
    configuration_file.sampling_rate_information.nrates  = atoi(sr_token[0].c_str());
    configuration_file.sampling_rate_information.samp    = atof(sr_token[1].c_str());
    configuration_file.sampling_rate_information.endsamp = atoi(sr_token[2].c_str());
    
    /* Date and time stamps */
    
    /* Reset variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i = 0;
    
    /* Read line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    dt_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        dt_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }
    
    /* Reset some variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i++;
    
    /* Read line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    dt_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        dt_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }
    
    /* Save data information of the time of the first data value in the data file */
    configuration_file.date_time_stamps.dt_dd = atoi(dt_token[0].substr(3, 2).c_str());
    configuration_file.date_time_stamps.dt_mm = atoi(dt_token[0].substr(0, 2).c_str());
    configuration_file.date_time_stamps.dt_yy = atoi(dt_token[0].substr(6, 4).c_str());
    configuration_file.date_time_stamps.hr_hh = atoi(dt_token[1].substr(0, 2).c_str());
    configuration_file.date_time_stamps.hr_mm = atoi(dt_token[1].substr(3, 2).c_str());
    configuration_file.date_time_stamps.hr_ss = atof(dt_token[1].substr(6, 9).c_str());
    
    /* Save data information of the trigger point */
    configuration_file.date_time_stamps.trig_dt_dd = atoi(dt_token[2].substr(3, 2).c_str());
    configuration_file.date_time_stamps.trig_dt_mm = atoi(dt_token[2].substr(0, 2).c_str());
    configuration_file.date_time_stamps.trig_dt_yy = atoi(dt_token[2].substr(6, 4).c_str());
    configuration_file.date_time_stamps.trig_hr_hh = atoi(dt_token[3].substr(0, 2).c_str());
    configuration_file.date_time_stamps.trig_hr_mm = atoi(dt_token[3].substr(3, 2).c_str());
    configuration_file.date_time_stamps.trig_hr_ss = atof(dt_token[3].substr(6, 9).c_str());
    
    /* Data file type (ASCII or Binary file) */
    
    /* Reset variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i = 0;
    
    /* Read line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    ft_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        ft_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }
    
    /* Save data information */
    configuration_file.data_file_type.file_type = ft_token[0];
    
    /* Time stamp multiplication factor */
    
    /* Reset variables */
    line_buffer.clear();
    found_new = 0;
    found_old = 0;
    i = 0;
    
    /* Read line */
    getline(file_stream[COMTRADE_FILE_CFG], line_buffer);
    
    /* Parse line buffer */
    found_new = line_buffer.find(",");
    found_old = found_new+1;
    ts_token[i] = line_buffer.substr(0, found_new);
    while (found_new != std::string::npos)
    {
        found_new = line_buffer.find(",", found_old);
        i++;
        ts_token[i] = line_buffer.substr(found_old, found_new-found_old);
        found_old = found_new+1;
    }
    
    /* Save data information */
    configuration_file.time_stamp_multiplier.timemult_factor = atof(ts_token[0].c_str());
    
    /* Set flag of parsed file */
    cfg_parse_file = true;
    
    return EXIT_SUCCESS;
}

string COMTRADE_parse::COMTRADE_get_cfg_general_information(const int& data_id)
{
    string data_return = "not_found";
    
    switch (data_id)
    {
        case cfg_data_station_name:
        {
            data_return = configuration_file.general_information.station_name;
            break;
        }
        case cfg_data_rec_dev_id:
        {
            data_return = configuration_file.general_information.rec_dev_id;
            break;
        }
        case cfg_data_rev_year:
        {
            data_return = configuration_file.general_information.rev_year;
            break;
        }
    }
    
    return data_return;
}

int COMTRADE_parse::COMTRADE_get_cfg_ad_channel_information(const int& data_id)
{
    int data_return = -1;
    
    switch (data_id)
    {
        case cfg_data_ch_tt:
        {
            data_return = configuration_file.channel_information.ch_tt;
            break;
        }
        case cfg_data_ch_ta:
        {
            data_return = configuration_file.channel_information.ch_ta;
            break;
        }
        case cfg_data_ch_td:
        {
            data_return = configuration_file.channel_information.ch_td;
            break;
        }
    }
    
    return data_return;
}

/* Analog channels */
double COMTRADE_parse::COMTRADE_get_cfg_analog_channel_d(int channel_id, int data_id)
{
    double data_return = -1;
    
    if (configuration_file.analog_channel_information.size() > 0)
    {
        for (int i=0; i<configuration_file.analog_channel_information.size(); i++)
        {
            if (configuration_file.analog_channel_information[i].ch_Ac == channel_id)
            {
                switch (data_id)
                {
                    case cfg_data_a_ch_a:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_a;
                        break;
                    }
                    case cfg_data_a_ch_b:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_b;
                        break;
                    }
                    case cfg_data_a_ch_skew:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_skew;
                        break;
                    }
                    case cfg_data_a_ch_pri_v:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_pri_v;
                        break;
                    }
                    case cfg_data_a_ch_sec_v:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_sec_v;
                        break;
                    }
                }
                break;
            }
        }
    }
    else
    {
        data_return = -2;
    }
    
    return data_return;
}

string COMTRADE_parse::COMTRADE_get_cfg_analog_channel_s(int channel_id, int data_id)
{
    string data_return = "channel_not_found";
    
    if (configuration_file.analog_channel_information.size() > 0)
    {
        for (int i=0; i<configuration_file.analog_channel_information.size(); i++)
        {
            if (configuration_file.analog_channel_information[i].ch_Ac == channel_id)
            {
                switch (data_id)
                {
                    case cfg_data_a_ch_id:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_id;
                        break;
                    }
                    case cfg_data_a_ch_phase:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_phase;
                        break;
                    }
                    case cfg_data_a_ch_ccbm:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_ccbm;
                        break;
                    }
                    case cfg_data_a_ch_units:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_units;
                        break;
                    }
                    case cfg_data_a_ch_PS:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_PS;
                        break;
                    }
                }
            }
        }
    }
    else
    {
        data_return = "empty_data";
    }
    
    return data_return;
}

int COMTRADE_parse::COMTRADE_get_cfg_analog_channel_i(int channel_id, int data_id)
{
    int data_return = -1;
    
    if (configuration_file.analog_channel_information.size() > 0)
    {
        for (int i=0; i<configuration_file.analog_channel_information.size(); i++)
        {
            if (configuration_file.analog_channel_information[i].ch_Ac == channel_id)
            {
                switch (data_id)
                {
                    case cfg_data_a_ch_min:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_min;
                        break;
                    }
                    case cfg_data_a_ch_max:
                    {
                        data_return = configuration_file.analog_channel_information[i].ch_max;
                        break;
                    }
                }
            }
        }
    }
    else
    {
        data_return -2;
    }
    
    return data_return;
}

/* Digital channels */
string COMTRADE_parse::COMTRADE_get_cfg_digital_channel(int channel_id, int data_id)
{
    string data_return = "channel_not_found";
    
    if (configuration_file.digital_channel_information.size() > 0)
    {
        for (int i=0; i<configuration_file.digital_channel_information.size(); i++)
        {
            if (configuration_file.digital_channel_information[i].ch_Dn == channel_id)
            {
                switch (data_id)
                {
                    case cfg_data_d_ch_id:
                    {
                        data_return = configuration_file.digital_channel_information[i].ch_id;
                        break;
                    }
                    case cfg_data_d_ch_phase:
                    {
                        data_return = configuration_file.digital_channel_information[i].ch_phase;
                        break;
                    }
                    case cfg_data_d_ch_ccbm:
                    {
                        data_return = configuration_file.digital_channel_information[i].ch_ccbm;
                        break;
                    }
                }
            }
        }
    }
    else
    {
        data_return = "empty_data";
    }
    
    return data_return;
}

int COMTRADE_parse::COMTRADE_get_cfg_digital_channel_status(int channel_id)
{
    int data_return = -1;
    
    if (configuration_file.digital_channel_information.size() > 0)
    {
        for (int i=0; i<configuration_file.digital_channel_information.size(); i++)
        {
            if (configuration_file.digital_channel_information[i].ch_Dn == channel_id)
            {
                data_return = configuration_file.digital_channel_information[i].ch_nstate;
            }
        }
    }
    else
    {
        data_return = -2;
    }
    
    return data_return;
}

double COMTRADE_parse::COMTRADE_get_cfg_line_frequency()
{
    return configuration_file.line_frequency.line_frequency;
}

double COMTRADE_parse::COMTRADE_get_cfg_sampling_rate()
{
    return configuration_file.sampling_rate_information.samp;
}

int COMTRADE_parse::COMTRADE_get_cfg_sampling_rate_data(int data_id)
{
    int data_return = -1;
    
    switch (data_id)
    {
        case cfg_data_nrates:
        {
            data_return = configuration_file.sampling_rate_information.nrates;
            break;
        }
        case cfg_data_endsamp:
        {
            data_return = configuration_file.sampling_rate_information.endsamp;
            break;
        }
    }
    
    return data_return;
}

double COMTRADE_parse::COMTRADE_get_cfg_time_stamp(int data_id)
{
    double data_return = -1;
    
    switch (data_id)
    {
        case cfg_data_dt_dd:
        {
            data_return = configuration_file.date_time_stamps.dt_dd;
            break;
        }
        case cfg_data_dt_mm:
        {
            data_return = configuration_file.date_time_stamps.dt_mm;
            break;
        }
        case cfg_data_dt_yy:
        {
            data_return = configuration_file.date_time_stamps.dt_yy;
            break;
        }
        case cfg_data_hr_hh:
        {
            data_return = configuration_file.date_time_stamps.hr_hh;
            break;
        }
        case cfg_data_hr_mm:
        {
            data_return = configuration_file.date_time_stamps.hr_mm;
            break;
        }
        case cfg_data_hr_ss:
        {
            data_return = configuration_file.date_time_stamps.hr_ss;
            break;
        }
        case cfg_data_trig_dt_dd:
        {
            data_return = configuration_file.date_time_stamps.trig_dt_dd;
            break;
        }
        case cfg_data_trig_dt_mm:
        {
            data_return = configuration_file.date_time_stamps.trig_dt_mm;
            break;
        }
        case cfg_data_trig_dt_yy:
        {
            data_return = configuration_file.date_time_stamps.trig_dt_yy;
            break;
        }
        case cfg_data_trig_hr_hh:
        {
            data_return = configuration_file.date_time_stamps.trig_hr_hh;
            break;
        }
        case cfg_data_trig_hr_mm:
        {
            data_return = configuration_file.date_time_stamps.trig_hr_mm;
            break;
        }
        case cfg_data_trig_hr_ss:
        {
            data_return = configuration_file.date_time_stamps.trig_hr_ss;
            break;
        }
    }
    
    return data_return;
}

string COMTRADE_parse::COMTRADE_get_cfg_file_type()
{
    return configuration_file.data_file_type.file_type;
}

double COMTRADE_parse::COMTRADE_get_cfg_time_multiplier()
{
    return configuration_file.time_stamp_multiplier.timemult_factor;
}

int COMTRADE_parse::COMTRADE_parse_dat_file()
{
    int data_return = 0;
    
    /* Check if dat file is parsed */
    if (dat_parse_file)
    {
        data_return = -1;
    }
    else
    {
        /* Open file stream */
        if (configuration_file.data_file_type.file_type == "ASCII")
        {
            file_stream[COMTRADE_FILE_DAT].open(file_list[COMTRADE_FILE_DAT].file_name.c_str(), ios::in);
            
            /* Check if file is opened */
            if (file_stream[COMTRADE_FILE_DAT].is_open())
            {
                COMTRADE_parse_ascii_data();
            }
            else
            {
                data_return = -2;
            }
        }
        else if (configuration_file.data_file_type.file_type == "BINARY")
        {
            file_stream[COMTRADE_FILE_DAT].open(file_list[COMTRADE_FILE_DAT].file_name.c_str(), ios::in | ios::binary);
            
            /* Check if file is opened */
            if (file_stream[COMTRADE_FILE_DAT].is_open())
            {
                COMTRADE_parse_binary_data();
            }
            else
            {
                data_return = -2;
            }
        }
        
        /* Set flag of parsed file */
        dat_parse_file = true;
    }
    
    return data_return;
}

int COMTRADE_parse::COMTRADE_parse_ascii_data()
{
    /* Status variable */
    double total_analog_channels  = 0;
    double total_digital_channels = 0;
    double size_of_record         = 0;
    double total_of_records       = 0;
    
    /* a and b multipliers */
    double m_a, m_b;
    
    /* Line stream buffer */
    string line_buffer, value_buffer;

    /* Line and column counters */
    int i = 0;
    int j = 0;
    
    /* Get configuration data */
    total_analog_channels  = configuration_file.channel_information.ch_ta;
    total_digital_channels = configuration_file.channel_information.ch_td;
    
    /* Determine size of record */
    size_of_record = 1+1+total_analog_channels+total_digital_channels;
    
    /* Total of records */
    ifstream temp_stream;
    string temp_string;
    
    temp_stream.open(file_list[COMTRADE_FILE_DAT].file_name.c_str(), ios::in);
    if (temp_stream.is_open())
    {
        while (!temp_stream.eof())
        {
            getline(temp_stream, temp_string);
            if (!temp_string.empty())
            {
                total_of_records++;
            }
        }
    }
    dat_total_records = total_of_records;
    
    temp_stream.close();
    
    /* read data */
    
    /* Found pointers */    
    size_t found_new = 0;
    size_t found_old = 0;
    
    while (!file_stream[COMTRADE_FILE_DAT].eof())
    {
        /* Temporary data file vector */
        dat_data_file temp_data_file;
        
        /* Read first line */
        getline(file_stream[COMTRADE_FILE_DAT], line_buffer);
        
        /* Parse first column buffer */
        found_new    = line_buffer.find(",");
        found_old    = found_new+1;
        value_buffer = line_buffer.substr(0, found_new);
        
        /* Save data information */
        temp_data_file.n = atoi(value_buffer.c_str());
        
        /* Reset variables */
        value_buffer.clear();
        
        /* Parse second column buffer */
        found_new = line_buffer.find(",", found_old);
        value_buffer = line_buffer.substr(found_old, found_new-found_old);
        found_old    = found_new+1;
        
        /* Save data information */
        temp_data_file.timestamp = atoi(value_buffer.c_str());
        
        /* Read analog channels information */
        for (i=0; i<total_analog_channels; i++)
        {
            /* Parse first column buffer */
            found_new = line_buffer.find(",", found_old);
            value_buffer = line_buffer.substr(found_old, found_new-found_old);
            found_old    = found_new+1;
            
            /* Save data information */
            data_analog_channels temp_analog_channels;
            temp_analog_channels.ak   = atoi(value_buffer.c_str());

            m_a = COMTRADE_get_cfg_analog_channel_d(i+1, cfg_data_a_ch_a);
            m_b = COMTRADE_get_cfg_analog_channel_d(i+1, cfg_data_a_ch_b);
            temp_analog_channels.ak_d = (temp_analog_channels.ak*m_a)+m_b;

            //temp_analog_channels.ak_d = 0;
            temp_data_file.analog_channels.push_back(temp_analog_channels);
        }
        
        /* Read digital channels information */
        for (j=0; j<total_digital_channels; j++)
        {
            /* Parse first column buffer */
            found_new = line_buffer.find(",", found_old);
            value_buffer = line_buffer.substr(found_old, found_new-found_old);
            found_old    = found_new+1;
            
            /* Save data information */
            data_digital_channels temp_digital_channels;
            temp_digital_channels.dm   = atoi(value_buffer.c_str());
            temp_digital_channels.dm_d = 0;
            temp_data_file.digital_channels.push_back(temp_digital_channels);
        }
        
        /* Save all analog channel datas */
        data_file.push_back(temp_data_file);
        
        /* Reset variables */
        line_buffer.clear();
        value_buffer.clear();
        
        found_new = 0;
        found_old = 0;
        
        i = 0;
        j = 0;
    }
    
    cout << data_file.size() << endl;
    
    return 0;
}

int COMTRADE_parse::COMTRADE_parse_binary_data()
{
    /* Status variable */
    int total_analog_channels  = 0;
    int total_digital_channels = 0;
    int size_of_record         = 0;
    int size_of_dc_record      = 0;
    int size_of_file           = 0;
    int total_of_records       = 0;
    
    /* a and b multipliers */
    double m_a, m_b;
    
    /* Line stream buffer */
    int line_buffer;

    /* Line and column counters */
    int i = 0;
    int j = 0;
    
    /* Get configuration data */
    total_analog_channels  = configuration_file.channel_information.ch_ta;
    total_digital_channels = configuration_file.channel_information.ch_td;
    
    /* Determine size of record in bytes */
    if (total_digital_channels == 0)
    {
        size_of_dc_record = 2;
    }
    else
    {
        size_of_dc_record = 2*(ceil(total_digital_channels/16));
    }
    size_of_record = 4+4+(2*total_analog_channels)+size_of_dc_record;
    
    /* Size of file in bytes */
    file_stream[COMTRADE_FILE_DAT].seekg(0, file_stream[COMTRADE_FILE_DAT].end);
    size_of_file = file_stream[COMTRADE_FILE_DAT].tellg();
    file_stream[COMTRADE_FILE_DAT].seekg(0, file_stream[COMTRADE_FILE_DAT].beg);
    
    /* Total of records */
    total_of_records = size_of_file/size_of_record;
    
    /* Save file informations */
    dat_total_records = total_of_records;
    dat_size_of_file  = size_of_file;
    
    for (j=0; j<total_of_records; j++)
    {
        /* Temporary data file vector */
        dat_data_file temp_data_file;
        
        /* Read sample number (4 bytes) */
        file_stream[COMTRADE_FILE_DAT].read((char*)&line_buffer, 4);
        
        /* Save sample number data */
        temp_data_file.n = line_buffer;
        
        /* Clear temp variable */
        line_buffer = 0;
        
        /* Read time stamp (4 bytes) */
        file_stream[COMTRADE_FILE_DAT].read((char*)&line_buffer, 4);
        
        /* Save time stamp data */
        temp_data_file.timestamp = line_buffer;
        
        /* Clear temp variable */
        line_buffer = 0;
        
        /* Read analog channels (2 bytes each)*/
        for (i=0; i<total_analog_channels; i++)
        {
            file_stream[COMTRADE_FILE_DAT].read((char*)&line_buffer, 2);
            
            /* Save data information */
            data_analog_channels temp_analog_channels;
            if (line_buffer < COMTRADE_MAX_BIT)
            {
                temp_analog_channels.ak = line_buffer;
            }
            else
            {
                line_buffer = line_buffer^0xffff;
                temp_analog_channels.ak = ~line_buffer;
            }
            /* Clear temp variable */
            line_buffer = 0;

//            m_a = COMTRADE_get_cfg_analog_channel_d(i+1, cfg_data_a_ch_a);
//            m_b = COMTRADE_get_cfg_analog_channel_d(i+1, cfg_data_a_ch_b);
//            temp_analog_channels.ak_d = (temp_analog_channels.ak*m_a)+m_b;
            
            temp_analog_channels.ak_d = 0;
            
            temp_data_file.analog_channels.push_back(temp_analog_channels);
        }
        
        /* Read digital channels (size_of_record bytes) */
        file_stream[COMTRADE_FILE_DAT].read((char*)&line_buffer, size_of_dc_record);
        
        /* Save data information */
        data_digital_channels temp_digital_channels;
        temp_digital_channels.dm   = line_buffer;
        temp_digital_channels.dm_d = 0;
        temp_data_file.digital_channels.push_back(temp_digital_channels);
        
        /* Clear temp variable */
        line_buffer = 0;
        
        /* Save all analog channel datas */
        data_file.push_back(temp_data_file);
    }
    
    /* debug */
    cout << "data_file.size()           " << data_file.size() << endl;
    
    return 0;
}

double COMTRADE_parse::COMTRADE_get_dat_analog_channel_sample(int sample, int channel, int multiplied = 0)
{
    double data_return = -1;
    
    for (int j=0; j<data_file.size(); j++)
    {
        if (data_file[j].n == sample)
        {
            for (int i=0; i<data_file[j].analog_channels.size(); i++)
            {
                if ((i+1) == channel)
                {
                    if (multiplied == 1)
                    {
                        data_return = data_file[j].analog_channels[i].ak_d;
                    }
                    else
                    {
                        data_return = data_file[j].analog_channels[i].ak;
                    }
                    break;
                }
            }
            break;
        }
    }
    
    return data_return;
}

int COMTRADE_parse::COMTRADE_get_dat_digital_channel_sample(int sample, int channel)
{
    double data_return = -1;
    
    for (int j=0; j<data_file.size(); j++)
    {
        if (data_file[j].n == sample)
        {
            for (int i=0; i<data_file[j].analog_channels.size(); i++)
            {
                if ((i+1) == channel)
                {
                    data_return = data_file[j].analog_channels[i].ak;
                    break;
                }
            }
            break;
        }
    }
    
    return data_return;
}

bool COMTRADE_parse::COMTRADE_check_bit_msb(const int& number)
{
    bool data_return = false;
    
    if (number > COMTRADE_MAX_BIT)
    {
        data_return = true;
    }
    
    return data_return;
}

int COMTRADE_parse::COMTRADE_get_dat_total_records()
{
    return dat_total_records;
}

int COMTRADE_parse::COMTRADE_get_dat_size_of_file()
{
    return dat_size_of_file;
}

int COMTRADE_parse::COMTRADE_get_dat_time_stamp(int sample)
{
    double data_return = -1;
    
    for (int j=0; j<data_file.size(); j++)
    {
        if (data_file[j].n == sample)
        {
            data_return = data_file[j].timestamp;
            break;
        }
    }
    
    return data_return;
}


void COMTRADE_parse::comtrade_teste()
{
    for (int j=0; j<data_file.size(); j++)
    {
        cout << "data_file[j].n         " << data_file[j].n << " " << data_file[j].timestamp << endl;
    }
}